package com.xuecheng.ucenter.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.ucenter.mapper.XcUserMapper;
import com.xuecheng.ucenter.mapper.XcUserRoleMapper;
import com.xuecheng.ucenter.model.dto.AuthParamsDto;
import com.xuecheng.ucenter.model.dto.XcUserExt;
import com.xuecheng.ucenter.model.po.XcUser;
import com.xuecheng.ucenter.model.po.XcUserRole;
import com.xuecheng.ucenter.service.AuthService;
import com.xuecheng.ucenter.service.WxAuthService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;

@Service("wx")
public class WxAuthServiceImpl implements AuthService, WxAuthService {
    @Autowired
    XcUserMapper xcUserMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private XcUserRoleMapper xcUserRoleMapper;

    @Autowired
    private WxAuthServiceImpl wxAuthServiceImpl;

    @Value("${weixin.appid}")
    String appid;
    @Value("${weixin.secret}")
    String secret;

    @Override
    public XcUserExt execute(AuthParamsDto authParamsDto) {
        //账号
        String username = authParamsDto.getUsername();
        XcUser user = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getUsername, username));
        if (user == null) {
            //返回空表示用户不存在
            throw new RuntimeException("账号不存在");
        }
        XcUserExt xcUserExt = new XcUserExt();
        BeanUtils.copyProperties(user, xcUserExt);
        return xcUserExt;
    }

    /**
     * 用于实现拿着授权码去获取令牌，解析令牌获取用户数据，将用户数据保存到数据库
     *
     * @param code
     * @return
     */
    @Override
    public XcUser wxAuth(String code) {
        //申请令牌
        Map<String, String> map = getAccess_token(code);
        String access_token = map.get("access_token");
        String openid = map.get("openid");
        //获取用户信息
        Map<String, String> userInfo = getUserInfo(access_token, openid);

        //非事务调用事务，使用代理对象
        XcUser xcUser = wxAuthServiceImpl.addUserToDb(userInfo);
        return xcUser;
    }

    @Transactional
    public XcUser addUserToDb(Map<String, String> userInfo) {
        //根据unionId去数据库判断是否存在此人
        /**
         * {
         * "openid":"OPENID",
         * "nickname":"NICKNAME",
         * "sex":1,
         * "province":"PROVINCE",
         * "city":"CITY",
         * "country":"COUNTRY",
         * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdm
         * "privilege":[
         * "PRIVILEGE1",
         * "PRIVILEGE2"
         * ],
         * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
         * }
         */
        String unionid = userInfo.get("unionid");
        XcUser xcUser = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getWxUnionid, unionid));
        if (xcUser!=null){
            return xcUser;
        }
        //新增数据
        xcUser=new XcUser();
        String userId = UUID.randomUUID().toString();
        String nickname = userInfo.get("nickname");
        xcUser.setId(userId);
        xcUser.setWxUnionid(unionid);
        xcUser.setUsername(unionid);//设置用户名登陆用
        xcUser.setPassword(unionid);
        xcUser.setNickname(nickname);//设置昵称
        xcUser.setName(nickname);//这个名字又是啥
        xcUser.setUtype("101001");//学生类型
        xcUser.setStatus("1");//用户状态
        xcUser.setCreateTime(LocalDateTime.now());
        xcUserMapper.insert(xcUser);

        //还需要向角色表中插入一个数据
        XcUserRole xcUserRole = new XcUserRole();
        xcUserRole.setId(UUID.randomUUID().toString());
        xcUserRole.setUserId(userId);
        xcUserRole.setRoleId("17");//学生角色
        xcUserRoleMapper.insert(xcUserRole);
        return xcUser;
    }

    /**
     * 通过code去申请令牌
     * https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
     * 返回数据
     * {
     * "access_token":"ACCESS_TOKEN",
     * "expires_in":7200,
     * "refresh_token":"REFRESH_TOKEN",
     * "openid":"OPENID",
     * "scope":"SCOPE",
     * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     *
     * @param code
     * @return
     */
    private Map<String, String> getAccess_token(String code) {
        String url_template = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        //将微信官网文档转化为合适的地址
        String url = String.format(url_template, appid, secret, code);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, null, String.class);
        String body = responseEntity.getBody();
        Map<String, String> result = JSON.parseObject(body, Map.class);
        return result;
    }

    /**
     * 通过令牌解析用户信息
     * <p>
     * http请求方式: GET
     * https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
     * <p>
     * 响应结果
     * {
     * "openid":"OPENID",
     * "nickname":"NICKNAME",
     * "sex":1,
     * "province":"PROVINCE",
     * "city":"CITY",
     * "country":"COUNTRY",
     * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
     * "privilege":[
     * "PRIVILEGE1",
     * "PRIVILEGE2"
     * ],
     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     *
     * @param access_token
     * @return
     */
    private Map<String, String> getUserInfo(String access_token, String openid) {
        String url_template = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
        String url = String.format(url_template, access_token, openid);
        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
        //由于编码方式不同，因此需要转码
        String result = new String(exchange.getBody().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        Map map = JSON.parseObject(result, Map.class);
        return map;
    }
}
